/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package videorent;

import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Iterator;

/** Representa a un asociado.
 *
 * @author Rafael
 */
public class Asociado extends Persona {

    /**Cantidad de articulos audiovisuales que puede alquilar un asociado*/
    private final int ARTICULOS_AUDIOVISUALES = 5;
    /**Cantidad de articulos interactivos que puede alquilar un asociado*/
    private final int ARTICULOS_INTERACTIVOS = 3;
    private String codigo; //B básico P Premium
    private String estado; // Si el asociado esta activo o suspendido
    private DireccionFiscal dirFiscal;
    private TarjetaCredito tC;
    // Lista de los operaciones (alquileres) que ha hecho el asociado
    private ArrayList<Object> operaciones; //Es una lista de objetos porq las operaciones pueden ser compra o alquiler
    private ArrayList<Multa> multas; //Es una lista de las multas para este asociado.
    
    /** Este es un constructor
     * @param codigo codigo del asociado
     * @param estado estatus del asociado, si es activo o premium
     * @param dirFiscal Direccion del asociado
     * @param tC Tarjeta de credito del asociado.
     * @param operaciones operaciones que ha hecho el asociado, por ejemplo alquileres.
     * @param cedula cedula del asociado
     * @param nombre nombre del asociado
     * @param apellido apellido del asociado
     * @param telefono telefono del asociado
     */
    public Asociado(String codigo, String estado, DireccionFiscal dirFiscal, TarjetaCredito tC, ArrayList<Object> operaciones, int cedula, String nombre, String apellido, int telefono) {
        super(cedula, nombre, apellido, telefono);
        this.codigo = codigo;
        this.estado = estado;
        this.dirFiscal = dirFiscal;
        this.tC = tC;
        this.operaciones = operaciones;
        this.multas = new ArrayList<Multa>();
    }

    /** Este es un constructor
     * @param codigo codigo del asociado
     * @param estado estatus del asociado, si es activo o premium
     * @param dirFiscal Direccion del asociado
     * @param tC Tarjeta de credito del asociado.
     * @param cedula cedula del asociado
     * @param nombre nombre del asociado
     * @param apellido apellido del asociado
     * @param telefono telefono del asociado
     */
    public Asociado(String codigo, String estado, DireccionFiscal dirFiscal, TarjetaCredito tC, int cedula, String nombre, String apellido, int telefono) {
        super(cedula, nombre, apellido, telefono);
        this.codigo = codigo;
        this.estado = estado;
        this.dirFiscal = dirFiscal;
        this.tC = tC;
        this.operaciones = new ArrayList<Object>();
        this.multas = new ArrayList<Multa>();
    }
	/** Obtiene una lista de multas al asociado
     * @return Lista de Multas del asociado
     */
    public ArrayList<Multa> getMultas() {
        return (ArrayList<Multa>) multas.clone();
    }

    /** Asigna una lista de multas al asociado
     * @param multas Multas del asociado
     */
    public void setMultas(ArrayList<Multa> multas) {
        this.multas = multas;
    }

    /** Devuelve el codigo del asociado
     * @return codigo del asociado
     */
    public String getCodigo() {
        return codigo;
    }

    /** Asigna el codigo del asociado
     * @param codigo codigo del asociado
     */
    public void setCodigo(String codigo) {
        this.codigo = codigo;
    }

    /** Devuelve la direccion fiscal del asociado
     * @return direccion fiscal del asociado
     */
    public DireccionFiscal getDirFiscal() {
        return dirFiscal.clone();
    }

    /** asigna la direccion fiscal del asociado
     * @param dirFiscal direccion fiscal del asociado
     */
    public void setDirFiscal(DireccionFiscal dirFiscal) {
        this.dirFiscal = dirFiscal;
    }

    /** Devuelve el estado del asociado
     * @return estado del asociado
     */
    public String getEstado() {
        return estado;
    }

    /** Asigna el estado del asociado
     * @param estado estado del asociado
     */
    public void setEstado(String estado) {
        this.estado = estado;
    }

    /** Devuelve las operaciones del asociado
     * @return operaciones realizadas por el asociado.
     */
    public ArrayList<Object> getOperaciones() {
        return (ArrayList<Object>) operaciones.clone();
    }

    /** Asigna las operaciones del asociado
     * @param operaciones operaciones realizadas por el asociado.
     */
    public void setOperaciones(ArrayList<Object> operaciones) {
        this.operaciones = operaciones;
    }

    /** Devuelve la tarjeta de credito del asociado
     * @return tarjeta de credito del asociado.
     */
    public TarjetaCredito gettC() {
        return tC.clone();
    }

    /** Asigna la tarjeta de credito del asociado
     * @param tC tarjeta de credito del asociado.
     */
    public void settC(TarjetaCredito tC) {
        this.tC = tC;
    }

    /**
     * Este metodo agrega una operacion de alquiler a la lista de operaciones
     * @param alq el total a pagar por los articulos a comprar o alquilar.
     */
    public void agregarOperacionAlquiler(Alquiler alq) {
        this.operaciones.add(alq);

    }

    /**
     * Este metodo obtiene el subtotal de los articulos de un asociado.
     * @return el total a pagar por los articulos a comprar o alquilar.
     */
    public double obtenerSubtotal() {
        double subtotal = 0;
        int i = 0;

        while (i < this.operaciones.size()) {
            Object op = (Object) operaciones.get(i);

            if (op instanceof Compra) {
                Compra c = (Compra) op;
                subtotal = subtotal + c.obtenerSubtotal();

            } else if (op instanceof Alquiler) {
                Alquiler al = (Alquiler) op;

                //Si obtenemos un alquiler cuyos articulos no estan pagos ..
                if ((al.getMontoEntregado() == 0) && (al.getTotal() == 0)) {
                    subtotal = subtotal + al.obtenerSubtotal();
                }

            }
            i++;
        }

        i = 0;

        while (i < this.getMultas().size()){
            Multa mult  = this.getMultas().get(i);
            subtotal = subtotal + mult.getMonto();
        }
        return subtotal;
    }

    /**
     * Este metodo actualiza los datos de la tarjeta de credito de un asociado.
     * @param numero numero de la tarjeta de credito.
     * @param banco  banco de la tarjeta de credito.
     * @param codSeg codigo de seguridad de la tarjeta de credito.
     * @param fechaVenc fecha de vencimiento de la tarjeta de credito.
     */
    public void actualizarTarjeta(String numero, String banco, String codSeg, GregorianCalendar fechaVenc) {
        tC.actualizarDatos(numero, banco, codSeg, fechaVenc);
    }

    /**
     * Este metodo obtiene la cantidad de los articulos interactivos a comprar o alquilar e
     * indica si se paso la cantidad maxima de articulos de este tipo para un asociado basico.
     * @return booleano que indica si se supera o no la cantidad maxima de articulos interactivos permitidos.
     */
    public boolean cantidadMaximaArticulosInteractivos() {

        ArrayList<Object> articulos = new ArrayList<Object>();
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = this.getOperaciones();
        Iterator it = venta.iterator();
        int cantidad = 0;
        boolean resultado = false;

        while (it.hasNext()) {
            //Obtengo la operacion
            Object op = it.next();
            // Si la operacion es una compra
            if (op instanceof Compra) {
                Compra comp = (Compra) op;
                if ((comp.getMontoEntregado() == 0) && (comp.getTotal() == 0)) {
                    cantidad = cantidad + comp.obtenerCantArticulosInteractivos();
                }

            } else if (op instanceof Alquiler) {
                Alquiler alq = (Alquiler) op;
                if ((alq.getMontoEntregado() == 0) && (alq.getTotal() == 0)) {
                    cantidad = cantidad + alq.obtenerCantArticulosInteractivos();
                }
            }
        }

        if (cantidad >= ARTICULOS_INTERACTIVOS) {
            resultado = true;
        } else {
            resultado = false;
        }
        return resultado;
    }

    /**
     * Este metodo obtiene la cantidad de los articulos audiovisuales a comprar o alquilar e
     * indica si se paso la cantidad maxima de articulos de este tipo para un asociado basico.
     * @return booleano que indica si se supera o no la cantidad maxima de articulos audiovisuales permitidos.
     */
    public boolean cantidadMaximaArticulosAudiovisuales() {

        ArrayList<Object> articulos = new ArrayList<Object>();
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = this.getOperaciones();
        Iterator it = venta.iterator();
        int cantidad = 0;
        boolean resultado = false;

        while (it.hasNext()) {
            //Obtengo la operacion
            Object op = it.next();
            // Si la operacion es una compra
            if (op instanceof Compra) {
                Compra comp = (Compra) op;
                if ((comp.getMontoEntregado() == 0) && (comp.getTotal() == 0)) {
                    cantidad = cantidad + comp.obtenerCantArticulosAudiovisuales();
                }

            } else if (op instanceof Alquiler) {
                Alquiler alq = (Alquiler) op;
                if ((alq.getMontoEntregado() == 0) && (alq.getTotal() == 0)) {
                    cantidad = cantidad + alq.obtenerCantArticulosAudiovisuales();
                }
            }
        }
        if (cantidad >= ARTICULOS_AUDIOVISUALES) {
            resultado = true;
        } else {
            resultado = false;
        }
        return resultado;
    }

    /**
     * Este metodo elimina los articulos a comprar por un asociado una vez que este los haya pagado.
     */
    public void eliminarArticulosCompra() {

        ArrayList<Object> articulos = new ArrayList<Object>();
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = this.getOperaciones();
        Iterator it = venta.iterator();

        while (it.hasNext()) {
            //Obtengo la operacion
            Object op = it.next();
            // Si la operacion es una compra
            if (op instanceof Compra) {
                Compra comp = (Compra) op;
                // Para cada compra obtenemos la lista de los articulos
                articulos = comp.getArticulos();

                //Borramos los articulos
                articulos.clear();

                comp.setArticulos(articulos);
                comp.setMontoEntregado(0);
                comp.setTotal(0);

                //Siempre vamos a tener una instancia de compra en el arreglo de operaciones
                break;
            }
        }
    }

    /**
     * Este metodo elimina los articulos a alquilar por un asociado una vez que este los haya pagado.
     */
    public void eliminarArticulosAlquiler() {

        ArrayList<Object> articulos = new ArrayList<Object>();
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = this.getOperaciones();
        Iterator it = venta.iterator();

        while (it.hasNext()) {
            //Obtengo la operacion
            Object op = it.next();
            // Si la operacion es un alquiler
            if (op instanceof Alquiler) {
                Alquiler alq = (Alquiler) op;

                //Si se trata de un alquiler no pago ..
                if ((alq.getMontoEntregado() == 0) && (alq.getTotal() == 0)) {
                    // Para cada alquiler obtenemos la lista de los articulos
                    articulos = alq.getArticulos();

                    //Borramos los articulos
                    articulos.clear();

                    alq.setArticulos(articulos);
                    alq.setMontoEntregado(0);
                    alq.setTotal(0);
                }
            }
        }
    }

    /**
     * Este metodo obtiene los articulos a comprar que fueron llevados a caja por un asociado.
     * @return Lista de articulos a comprar.
     */
    public ArrayList<Object> obtenerArticulosCompra() {
        ArrayList<Object> articulos = new ArrayList<Object>();
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = this.getOperaciones();
        Iterator it = venta.iterator();

        while (it.hasNext()) {
            //Obtengo la operacion
            Object op = it.next();
            // Si la operacion es una compra
            if (op instanceof Compra) {
                Compra comp = (Compra) op;
                // Para cada compra obtenemos la lista de los articulos
                articulos = comp.getArticulos();
            }
        }

        return articulos;
    }

    /**
     * Este metodo obtiene los articulos a alquilar que fueron llevados a caja por un asociado.
     * @return Lista de articulos a alquilar.
     */
    public ArrayList<Object> obtenerArticulosAlquiler() {
        int i = 0;
        //Obtenemos los alquileres
        ArrayList<Alquiler> artAlquiler = this.obtenerAlquileres();

        ArrayList<Object> articulosAlquilar = new ArrayList<Object>();

        //Iteramos sobre la lista de alquileres para obtener los articulos que no estan pagos todavia
        //para este dia
        while (i < artAlquiler.size()) {
            Alquiler alquil = artAlquiler.get(i);

            //Si estamos en presencia de una operacion de alquiler que no se ha pagado todavia ..
            if ((alquil.getTotal() == 0) && (alquil.getMontoEntregado() == 0)) {

                //Obtenemos los articulos a alquilar
                articulosAlquilar = alquil.getArticulos();

                if (!articulosAlquilar.isEmpty()) {

                    //Anhadimos un nuevo alquiler vacio a la lista de operaciones
                    this.agregarOperacionAlquiler(new Alquiler());
                }

                //Nos salimos del bucle pues solo debe ocurrir que tengamos un alquiler por pagar
                break;
            }
            i++;
        }
        
        return articulosAlquilar;
    }

    /**
     * Este metodo setea el valor de monto total y monto entregado para los articulos llevados a caja
     * para alquiler y que luego son pagos.
     */
    public void setearAlquiler(double total, double montoEntregado) {

        ArrayList<Alquiler> listAlquileres = new ArrayList<Alquiler>();
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = this.getOperaciones();
        Iterator it = venta.iterator();

        while (it.hasNext()) {
            //Obtengo la operacion
            Object op = it.next();
            // Si la operacion es un alquiler
            if (op instanceof Alquiler) {
                Alquiler comp = (Alquiler) op;

                //Obtenemos el alquiler que guarda los articulos llevados a caja
                if ((comp.getTotal() == 0) && (comp.getMontoEntregado() == 0)) {
                    comp.setMontoEntregado(montoEntregado);
                    comp.setTotal(total);
                }
                break;
            }
        }
    }

    /**
     * Este metodo obtiene los alquileres de un asociado.
     * @return Lista de Alquileres.
     */
    public ArrayList<Alquiler> obtenerAlquileres() {

        ArrayList<Alquiler> listAlquileres = new ArrayList<Alquiler>();
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = this.getOperaciones();
        Iterator it = venta.iterator();

        while (it.hasNext()) {
            //Obtengo la operacion
            Object op = it.next();
            // Si la operacion es un alquiler
            if (op instanceof Alquiler) {
                Alquiler comp = (Alquiler) op;

                //Guardamos el alquiler en una lista de alquileres
                listAlquileres.add(comp);
            }
        }
        return listAlquileres;
    }

    /**
     * Este metodo guarda un articulo en la lista de articulos para comprar de un asociado.
     * @param articulo Articulo que se guarda en la lista de articulos para comprar.
     */
    public void guardarArticuloCompra(Articulo articulo) {
        ArrayList<Object> articulos = new ArrayList<Object>();
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = operaciones;



        //Se guarda un articulo para su compra por primera vez
        if (venta.isEmpty()) {

            articulos.add(articulo);
            Compra c = new Compra(articulos);
            Alquiler al = new Alquiler(0, 0, new ArrayList<Object>());
            venta.add(c);
            venta.add(al);
        } else {

            //Iteramos sobre la lista de de operaciones para obtener la compra
            Iterator it = venta.iterator();

            while (it.hasNext()) {
                //Obtengo la operacion
                Object op = it.next();
                // Si la operacion es una compra
                if (op instanceof Compra) {
                    Compra comp = (Compra) op;
                    // Para cada compra obtenemos la lista de los articulos
                    articulos = comp.getArticulos();

                    //Agregamos el articulo a la lista
                    articulos.add(articulo);
                    comp.setArticulos(articulos);
                }
            }
        }
    }

    /**
     * Este metodo guarda un articulo en la lista de articulos para alquilar de un asociado.
     * @param articulo Articulo que se guarda en la lista de articulos para comprar.
     */
    public void guardarArticuloAlquiler(Articulo articulo) {
        ArrayList<Object> articulos = new ArrayList<Object>();
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = operaciones;

        //Se guarda un articulo para su alquiler por primera vez
        if (venta.isEmpty()) {
            articulos.add(articulo);
            Alquiler al = new Alquiler(articulos);
            Compra co = new Compra();
            venta.add(al);
            venta.add(co);
        } else {
            //Iteramos sobre la lista de de operaciones para obtener el alquiler
            Iterator it = venta.iterator();

            while (it.hasNext()) {
                //Obtengo la operacion
                Object op = it.next();
                // Si la operacion es un alquiler
                if (op instanceof Alquiler) {

                    Alquiler alq = (Alquiler) op;
                    // Para cada alquiler obtenemos aquel que no este pago todavia
                    if ((alq.getTotal() == 0) && (alq.getMontoEntregado() == 0)) {
                        articulos = alq.getArticulos();

                        //Agregamos el articulo a la lista
                        articulos.add(articulo);
                        alq.setArticulos(articulos);

                        //Dejamos de buscar pues solo tendremos un alquiler sin pagar
                        break;
                    }
                }
            }
        }
    }

    // Funciones Rafael
    public boolean chequearValidezTarjeta(GregorianCalendar fecha) {
        return (this.gettC()).proximaVencer(fecha);
    }

    /**
     * Este metodo devuelve un String con la información de un asociado
     * cumpliendo con el formato de salida del archivo.
     * @return  String Informacion de Asociado en forma de String.
     */
    // ATENCION
    // Pendiente con obtenerDatos* arreglar luego de responder la duda
    public String obtenerDatosAsociado() {
        String linea = "";
        linea += this.getCodigo() + " & ";
        linea += this.getEstado() + " & ";
        linea += this.getCedula() + " & ";
        linea += this.getCedula() + " & ";
        linea += this.getNombre() + " & ";
        linea += this.getApellido() + " & ";
        linea += this.getTelefono() + " & ";
        linea += (this.getDirFiscal()).obtenerDatosDireccionF() + " & ";
        linea += (this.gettC()).obtenerDatosTC();

        //System.out.println(linea);
        return linea;
    }

    /** Esta funcion obtiene los prestamos de un asociaodo en forma de un string
     * @return Prestamos.
     */
    public String obtenerPrestamos() {
        // Obtenemos las Operaciones del asociado
        ArrayList<Object> venta = this.getOperaciones();
        Iterator it = venta.iterator();
        // Obtenemos el codgigo del asociado
        String linea = "";
        Iterator iOper;
        Iterator itArt;
        Object oAsoc, oOperacion, oArt;
        Alquiler alq;
        Articulo a;
        ArrayList<Object> articulos;
        int cantidad = 0;

        // Para cada uno de las operaciones del asociado
        iOper = (this.getOperaciones()).iterator();
        while (iOper.hasNext()) {
            oOperacion = iOper.next();
            // Si es un aqluiler
            if (oOperacion instanceof Alquiler) {
                alq = (Alquiler) oOperacion;
                articulos = alq.getArticulos();
                itArt = articulos.iterator();
                // Para cada uno de los articulos del asociado
                while (itArt.hasNext()) {
                    oArt = itArt.next();
                    if (oArt instanceof Pelicula) {
                        Pelicula p = (Pelicula) oArt;
                        cantidad = alq.objetosIguales(p.getCodigo());
                        linea += this.getCodigo() + " & " + cantidad + " & "
                                + p.obtenerDatos().substring(4).replaceAll("\\s&\\s\\d+/\\d+/\\d\\d\\d\\d", "")
                                + "\n";
                    } else if (oArt instanceof TemporadaSerie) {
                        TemporadaSerie t = (TemporadaSerie) oArt;
                        cantidad = alq.objetosIguales(t.getCodigo());
                        linea += this.getCodigo() + " & " + cantidad + " & "
                                + t.obtenerDatos().substring(4).replaceAll("\\s&\\s\\d+/\\d+/\\d\\d\\d\\d", "")
                                + "\n";
                    } else if (oArt instanceof JuegoEducativo) {
                        JuegoEducativo je = (JuegoEducativo) oArt;
                        cantidad = alq.objetosIguales(je.getCodigo());
                        linea += this.getCodigo() + " & " + cantidad + " & "
                                + je.obtenerDatos().substring(4).replaceAll("\\s&\\s\\d+/\\d+/\\d\\d\\d\\d", "")
                                + "\n";
                    } else if (oArt instanceof JuegoRecreativo) {
                        JuegoRecreativo jr = (JuegoRecreativo) oArt;
                        cantidad = alq.objetosIguales(jr.getCodigo());
                        linea += this.getCodigo() + " & " + cantidad + " & "
                                + jr.obtenerDatos().substring(4).replaceAll("\\s&\\s\\d+/\\d+/\\d\\d\\d\\d", "")
                                + "\n";
                    }
                }
            }
        }
        return linea;
    }
}
